package com.tim.third.annotation;

import org.aopalliance.intercept.MethodInterceptor;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.internal.engine.ValidatorImpl;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;

import javax.validation.*;
import javax.validation.constraints.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Set;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @Description: hibernate注解
 * @Version 1.0, 2021/5/17
 * @Author Tim
 */
public class CheckAnnotation {
    // https://cjdhy.blog.csdn.net/article/details/121747093
    public static void validAnno(){

        // jdk；用于方法、方法参数、方法返回值；声明校验
        // 属性，嵌套校验
        Valid valid;
        // spring；不嵌套(需联合@Valid)，可分组校验
        // 用于类，声明bean校验，如配置文件bean
        // 用于方法、入参；声明校验
        Validated validated;
    }

    /**
     * 简单对象校验
     */
    public static void main(String[] args) {
        //初始化一个校验器工厂
        ValidatorFactory validatorFactory = Validation
                .byProvider(HibernateValidator.class)
                .configure()
                //校验失败是否立即返回： true-遇到一个错误立即返回不在往下校验，false-校验完所有字段才返回
                .failFast(false)
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        Object s=new Object ();
//        s.setName(" ");

        Set<ConstraintViolation<Object>> result=validator.validate(s);
        System.out.println("遍历输出错误信息:");
        //getPropertyPath() 获取属性全路径名
        //getMessage() 获取校验后的错误提示信息
        result.forEach(r-> System.out.println(r.getPropertyPath()+":"+r.getMessage()));
    }

    /**
     * null相关
     */
    public static void nullRelated(){
        Null Null;
        NotNull notNull;
    }

    /**
     * 数字
     */
    public static void number(){
        Min min;
        Max max;
        DecimalMin decimalMin;
        DecimalMax decimalMax;
        Digits digits;
        Negative negative;
        Positive positive;
        NegativeOrZero negativeOrZero;
        PositiveOrZero positiveOrZero;

    }

    /**
     * 字符串、集合
     */
    public static void stringAndCollection(){
        Size size;
        NotBlank notBlank;// 仅用于字符串
        Pattern pattern;
        Email email;
    }

    /**
     *  时间
     */
    public static void time(){
        Past past;
        Future future;
        PastOrPresent pastOrPresent;
        FutureOrPresent futureOrPresent;
    }
    //

    /**
     *  布尔值
     */
    public static void bool(){
        AssertTrue assertTrue;
        AssertFalse assertFalse;

    }

    public static void valid(){
        // hibernate校验
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(null);
        if (violations != null && !violations.isEmpty()) {
            // 可遍历拿到全部校验信息
            ConstraintViolation<Object> violation = violations.iterator().next();
            System.out.println(violation.getMessage());;
        }
    }

    public static void check(){
        /* step1，对象内注解*/
        Validator validator;
        ValidatorImpl hibernateValidator;
        // 适配java、spring的Validator；实际校验由hibernateValidator完成
        SpringValidatorAdapter springValidatorAdapter;
        Validation validation;// 获取validator
        Validation.buildDefaultValidatorFactory().getValidator();

        /* step2，controller形参列表注解*/
        // https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-config-validation
        // https://blog.csdn.net/zhenwei1994/article/details/81460419
        LocalValidatorFactoryBean validatorFactoryBean;// 继承SpringValidatorAdapter
        Valid valid;// java；嵌套校验时需要标记对应字段
        Validated validated;//spring封装，支持分组校验
        BindingResult bindingResult;// 校验结果

        // 实现BeanPostProcessor；切面嵌入
        MethodValidationPostProcessor methodValidationPostProcessor;
        MethodValidationInterceptor methodValidationInterceptor;// 校验逻辑
        MethodInterceptor methodInterceptor;

    }

    // 自定义
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Repeatable(SelfConstrainsAnnotation.List.class)
    @Documented
    @Constraint(validatedBy = {SelfConstraintValidator.class })
    public @interface SelfConstrainsAnnotation{
        String value() default "";

        @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
        @Retention(RUNTIME)
        @Documented
        @interface List {

            SelfConstrainsAnnotation[] value();
        }
    }

    public class SelfConstraintValidator implements ConstraintValidator<SelfConstrainsAnnotation, Object> {

        @Override
        public void initialize(SelfConstrainsAnnotation constraintAnnotation) {
        }

        /**
         * Implements the validation logic.
         * The state of {@code value} must not be altered.
         * <p>
         * This method can be accessed concurrently, thread-safety must be ensured
         * by the implementation.
         *
         * @param value   object to validate
         * @param context context in which the constraint is evaluated
         * @return {@code false} if {@code value} does not pass the constraint
         */
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            return false;
        }
    }

}
